package com.sudo.service.admin.task;

import com.sudo.common.annotation.Note;
import com.sudo.common.annotation.TaskComponent;
import com.sudo.common.component.StringRedisUtil;
import com.sudo.common.enums.SysServerStatus;
import com.sudo.common.component.RedisKeys;
import com.sudo.common.enums.SysStatus;
import com.sudo.common.utils.JsonUtil;
import com.sudo.common.utils.LocalDateTimeUtil;
import com.sudo.dao.admin.entity.SysAutoRole;
import com.sudo.dao.admin.entity.SysServerNode;
import com.sudo.dao.admin.entity.SysUser;
import com.sudo.dao.admin.entity.SysUserBehavior;
import com.sudo.dao.admin.entity.SysUserStsDay;
import com.sudo.dao.admin.mapper.SysUserBehaviorMapper;
import com.sudo.dao.admin.model.vo.StsBehaviorVO;
import com.sudo.rpc.api.common.Constant;
import com.sudo.service.admin.mail.MailPojo;
import com.sudo.service.admin.mail.MailPojoUtil;
import com.sudo.service.admin.mail.MailService;
import com.sudo.service.admin.service.*;
import com.sudo.service.annotation.VerifyTaskRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.time.LocalDate;
import java.util.*;

@Slf4j
@TaskComponent
public class AdminTaskModule {

    @Resource
    public StringRedisUtil stringRedisUtil;
    @Resource
    private SysUserService sysUserService;
    @Resource
    private SysUserBehaviorMapper sysUserBehaviorMapper;
    @Resource
    private SysUserStsDayService sysUserStsDayService;
    @Resource
    private SysUserStsMonthService sysUserStsMonthService;
    @Resource
    private SysMyStsDayService sysMyStsDayService;
    @Resource
    private SysMyStsMonthService sysMyStsMonthService;
    @Resource
    private SysAutoRoleService sysAutoRoleService;
    @Resource
    private SysServerNodeService sysServerNodeService;
    @Resource
    private MailService mailService;


    /**
     * 建议：按秒更新，用户行为记录
     */
    @VerifyTaskRequest
    @Note(desc = "用户行为记录",params = "count(Integer,true,2,获取数据次数)")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void addUserBehaviorToMysqlFromRedis(Map<String,Object> paramMap) {
        int count = Integer.parseInt(paramMap.get("count").toString());
        List<SysUserBehavior> sysUserBehaviorList = new ArrayList<>();
        for (int i=0;i<count;i++){
            String jsonData = stringRedisUtil.lRightPop(RedisKeys.REDIS_USER_BEHAVIOR);
            if (StringUtils.isNotBlank(jsonData)) {
                SysUserBehavior sysUserBehavior = JsonUtil.jsonToPojo(jsonData, SysUserBehavior.class);
                sysUserBehaviorList.add(sysUserBehavior);
            }
        }
        if (CollectionUtils.isNotEmpty(sysUserBehaviorList)) {
            sysUserBehaviorMapper.insertList(sysUserBehaviorList);
        }
    }


    /**
     * 建议：每天 凌晨 00:05:00 执行 (更新昨天的用户统计)
     */
    @VerifyTaskRequest
    @Note(desc = "用户统计-按天",params = "offset(Integer,true,2,日期偏移量)")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void stsUserBehaviorAndLoginByDay(Map<String,Object> paramMap) {
        int offset = Integer.parseInt(paramMap.get("offset").toString());
        LocalDate localDate = LocalDate.now().plusDays(offset);
        sysUserStsDayService.stsUserBehaviorByDay(localDate);
    }

    /**
     * 建议：每月1日 凌晨 00:05:00 执行 (更新上月的用户统计)
     *
     */
    @VerifyTaskRequest
    @Note(desc = "用户统计-按月",params = "offset(Integer,true,2,月份偏移量)")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void stsUserBehaviorAndLoginByMonth(Map<String,Object> paramMap) {
        int offset = Integer.parseInt(paramMap.get("offset").toString());
        LocalDate localDate = LocalDate.now().plusMonths(offset);
        int year = localDate.getYear();
        int month = localDate.getMonthValue();
        sysUserStsMonthService.stsUserBehaviorByMonth(year,month);
    }

    /**
     * 建议：每天 凌晨 00:05:00 执行 (更新昨天的我的统计)
     */
    @VerifyTaskRequest
    @Note(desc = "我的统计-按天",params = "offset(Integer,true,2,日期偏移量)")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void stsMyBehaviorAndLoginByDay(Map<String,Object> paramMap) {
        int offset = Integer.parseInt(paramMap.get("offset").toString());
        LocalDate localDate = LocalDate.now().plusDays(offset);
        List<SysUser> allUsername = sysUserService.getAllUsername();
        for (SysUser sysUser : allUsername) {
            sysMyStsDayService.stsMyBehaviorByDay(localDate,sysUser.getUsername());
        }
    }

    /**
     * 建议：每月1日 凌晨 00:05:00 执行 (更新上月的我的统计)
     *
     */
    @VerifyTaskRequest
    @Note(desc = "我的统计-按月",params = "offset(Integer,true,2,月份偏移量)")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void stsMyBehaviorAndLoginByMonth(Map<String,Object> paramMap) {
        int offset = Integer.parseInt(paramMap.get("offset").toString());
        LocalDate localDate = LocalDate.now().plusMonths(offset);
        int year = localDate.getYear();
        int month = localDate.getMonthValue();
        List<SysUser> allUsername = sysUserService.getAllUsername();
        for (SysUser sysUser : allUsername) {
            sysMyStsMonthService.stsMyBehaviorByMonth(year,month,sysUser.getUsername());
        };
    }

    @VerifyTaskRequest
    @Note(desc = "用户过期检测")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void updateAutoRoleStatus(){
        List<SysAutoRole> sysAutoRoleList = sysAutoRoleService.getExpirationAutoRole();

        int affectCount = 0;
        if (CollectionUtils.isNotEmpty(sysAutoRoleList)){
            for (SysAutoRole sysAutoRole : sysAutoRoleList) {
                if (SysStatus.ON.name().equals(sysAutoRole.getStatus())) {
                    affectCount += sysAutoRoleService.updateAutoRoleStatus(sysAutoRole);
                }
            }
        }
        log.info("更新过期用户状态{}条",affectCount);
    }

    /**
     * 建议：
     *  # 每天早上 9:00 发送邮件
     *  # 每周一早上 9:00 发送邮件
     *  # 每月1号早上 9：00 发送邮件
     *
     */
    @VerifyTaskRequest
    @Note(desc = "用户行为数据邮件",params = "from(Integer,true,-1,偏移量（小）)" +
            "|to(Integer,true,-1,偏移量（大）)|unit(String,true,week,单位（day/week/month）)" +
            "|email(String,true,xxx@qq.com...,邮箱（用‘逗号’分割）)")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void emailAboutBehaviorAndLogin(Map<String,Object> paramMap) {
        int from = Integer.parseInt(paramMap.get("from").toString());
        int to = Integer.parseInt(paramMap.get("to").toString());
        String unit = paramMap.get("unit").toString();
        String email = paramMap.get("email").toString();
        LocalDate localDate = LocalDate.now();

        List<LocalDate> dateList = LocalDateTimeUtil.getDateList(localDate, from, to, unit);
        LocalDate minDate = dateList.stream().min(Comparator.naturalOrder()).get();
        LocalDate maxDate = dateList.stream().max(Comparator.naturalOrder()).get();

        List<SysUserStsDay> sysUserStsDayList = sysUserStsDayService.getSysUserStsDayList(minDate, maxDate);

        List<StsBehaviorVO> stsBehavior = sysUserStsDayService.getStsBehavior(dateList, sysUserStsDayList);

        // 发送邮件
        MailPojo mailPojo = MailPojoUtil.stsUserBehaviorMail(email, stsBehavior,minDate,maxDate);

        mailService.sendMimeMail(mailPojo);
    }

    @VerifyTaskRequest
    @Note(desc = "服务在线检测")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void checkServerNode()  {
        List<SysServerNode> sysServerNodeList = sysServerNodeService.queryAllServerNodes();
        for (SysServerNode sysServerNode : sysServerNodeList) {
            String[] split = sysServerNode.getServer().split(":");
            try {
                Registry remoteRegistry = LocateRegistry.getRegistry(split[0], Integer.parseInt(split[1]));
                remoteRegistry.lookup(Constant.registryCenter);
                sysServerNodeService.updateServerNodeStatus(sysServerNode.getServer(), SysServerStatus.ONLINE.name());
            } catch (RemoteException | NotBoundException e) {
                sysServerNodeService.updateServerNodeStatus(sysServerNode.getServer(), SysServerStatus.OFFLINE.name());
                log.error("服务{}离线",sysServerNode.getServer());
            }
        }
    }

}
